home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-09-29 | 8.7 KB | 309 lines | [TEXT/KAHL] |
- #include <Retrace.h>
- #include <Devices.h>
- #include <SegLoad.h>
- #include <Timer.h>
-
- #include <math.h>
- #include <iostream.h>
-
- #include "C_randomizer.h"
- #include "flowsettings.h"
- #include "vretrace.h"
- #include "macutilities.h"
- #include "phaser.h"
- #include "screenarea.h"
- #include "screendots.h"
- #include "dotcollection.h"
- #include "flowdots.h"
-
- flowdots::flowdots( int numbits, int xpos, int ypos,
- int aantaldots, int lifetime, double how_often)
- : flowparams()
- , dotcollection( aantaldots)
- , phaser( lifetime)
- , flowsettings()
- , screendots( numbits, xpos, ypos, aantaldots)
- {
- time_of_last_apply_flow_call = 0;
-
- framerate = framerate_of_main_monitor();
-
- if( how_often > 0.0)
- {
- updaterate = how_often;
- auto_timing = false;
- } else {
- auto_timing = true;
- }
- compute_matrices();
- }
-
- flowdots::flowdots( int numbits, screen_position where,
- int aantaldots, int lifetime, double how_often)
- : flowparams()
- , dotcollection( aantaldots)
- , phaser( lifetime)
- , flowsettings()
- , screendots( numbits, where, aantaldots)
- {
- time_of_last_apply_flow_call = 0;
-
- framerate = framerate_of_main_monitor();
-
- if( how_often > 0.0)
- {
- updaterate = how_often;
- auto_timing = false;
- } else {
- auto_timing = true;
- }
- compute_matrices();
- }
-
- void flowdots::compute_addresses()
- {
- apply_flow(); // computes next position of all dots
- //
- // could use dotcollection::numdots, as well
- //
- #define help_the_optimizer
-
- #ifdef help_the_optimizer
- const int loopend = screendots::numdots;
- const int the_shift = coord_shift; // aids the optimizer
- unsigned char **dot_address = dot_addresses;
- short *xcoord = xcoords;
- short *ycoord = ycoords;
- for( int i = 0; i < loopend; i++)
- {
- *dot_address++ =
- &screen[ *ycoord++ >> the_shift][ *xcoord++ >> the_shift];
- }
- #else
- for( int i = 0; i < screendots::numdots; i++)
- {
- dot_addresses[ i] =
- &screen[ ycoords[ i] >> coord_shift][ xcoords[ i] >> coord_shift];
- }
- #endif
- #undef help_the_optimizer
- }
-
- void flowdots::apply_flow()
- {
- (void)major_step();
- if( auto_timing)
- {
- //
- // maintain time yourself:
- //
- const unsigned long now_micros = readMicroseconds();
- if( time_of_last_apply_flow_call == 0)
- {
- //
- // first time around: 'smart' guess
- //
- updaterate = framerate / 2;
- } else {
- #ifdef THINK_CPLUS
- //
- // prevents a call of '_UTOX96' (SC++ 7.0 bug)
- // (941121: bug no longer really present in 7.0.4. It used to be
- // that a call to '_UTOX96' was generated, where this function
- // was not present in 'ANSI++ 881' (or any other '881 library).
- // With SC++ 7.0.4 the call to '_UTOX91' is still generated, but
- // no link errors occur, but for now, keep using a long instead
- // of an unsigned long. (this replaces a subroutine call with a
- // FPU divide. The latter is much faster, and delivers the same
- // result, as long as this code doesn't run on a Pentium ;-)
- //
- const long delay = now_micros - time_of_last_apply_flow_call;
- #else
- const unsigned long delay = now_micros - time_of_last_apply_flow_call;
- #endif
- updaterate = 1000000.0 / (double)delay;
- }
- time_of_last_apply_flow_call = now_micros;
- compute_matrices();
- }
- short *the_xcoord = xcoords;
- short *the_ycoord = ycoords;
- //
- // Note: there must be _exactly_ one '*the_xcoord++ = …' and _exactly_ one
- // '*the_ycoord++ = …' in every possible path through the loop.
- //
- short_long_hack the_hack;
- const int loopend = dotcollection::numdots; // could also use screendots::numdots
-
- for( int i = 0; i < loopend; i++)
- {
- if( minor_step() != 0)
- {
- //
- // compute new position of dot
- //
- const long prev_x = (long) *the_xcoord;
- const long prev_y = (long) *the_ycoord;
- //
- // Note: the expression below was optimized, but now gives slightly different
- // results. I haven't thought about its ramifications, yet.
- // 941206: The difference is thought to be too minor to be visible.
- //
- // const long new_x = ((prev_x * x11) >> 15)
- // + ((prev_y * x12) >> 15) + trans_x + prev_x;
- //
- const long new_x =
- (((prev_x * x11) + (prev_y * x12)) >> 15) + trans_x + prev_x;
- if( new_x != (short)new_x)
- {
- //
- // use one call of 'step' and split the result in two:
- //
- the_hack.ulong = randomizer_step();
- *the_xcoord++ = the_hack.shorties.left;
- *the_ycoord++ = the_hack.shorties.right;
- } else {
- //
- // Note: the expression below was optimized, but now gives slightly different
- // results. I haven't thought about its ramifications, yet.
- // 941206: The difference is thought to be too minor to be visible.
- //
- // const long new_y = ((prev_x * x21) >> 15)
- // + ((prev_y * x22) >> 15) + trans_y + prev_y;
- //
- const long new_y =
- (((prev_x * x21) + (prev_y * x22)) >> 15) + trans_y + prev_y;
- if( new_y != (short)new_y)
- {
- //
- // use one call of 'step' and split the result in two:
- //
- the_hack.ulong = randomizer_step();
- *the_xcoord++ = the_hack.shorties.left;
- *the_ycoord++ = the_hack.shorties.right;
- } else {
- *the_xcoord++ = (short)new_x;
- *the_ycoord++ = (short)new_y;
- }
- }
- } else {
- //
- // dot surpassed its lifetime
- //
- the_hack.ulong = randomizer_step();
- *the_xcoord++ = the_hack.shorties.left;
- *the_ycoord++ = the_hack.shorties.right;
- }
- }
- }
-
- void flowdots::compute_matrices()
- {
- //
- // The translation will not be stored in the matrix (in fact it can't be).
- // There is no need to preprocess it since its parameters are available
- // in the 'translation' parameter (translation.x, translation.y);
- //
- // view a shear in direction d as a rotation over -d, a 'natural shear',
- // and a rotation back over d.
- // Let d be the shear angle and m its magnitude. The shear matrix can than
- // be calculated as:
- //
- // ( cos( d) -sin( d) ) ( m 0 ) ( cos(-d) -sin(-d) )
- // ( sin( d) cos( d) ) ( 0 1/m) ( sin(-d) cos(-d) )
- //
- // Moreover we have sin(-x) = -sin( x), cos(-x) = cos( x)
- // and we can define c := cos( d), s := sin( d) for brevity.
- // We then find
- //
- // ( c -s ) ( m 0 ) ( c s )
- // ( s c ) ( 0 1/m) (-s c )
- //
- // which (with c2 = c squared, etc) is equal to
- //
- // ( c2 m + s2/m cs (m - 1/m) )
- // ( cs (m - 1/m) s2 m + c2/m )
- //
- // These values will be put in the transformation matrix as follows:
- //
- // ( xform[ 0] xform[ 1] )
- // ( xform[ 2] xform[ 3] )
- //
- // (well, almost in the transformation matrix; it appears to be simpler
- // to use copies called xform_0, xform_1, xform_2, xform_3)
- // Also, we do not store the transformation matrix, but we store the
- // difference between the transformation matrix and the identity matrix.
- //
- // But first, we derive 'per frame' values for the flow parameters.
- //
- const double scaled_expansion = scale( expansion, updaterate);
- const double scaled_shear_magnitude = scale( shear_magnitude, updaterate);
- const double scaled_rotation = rotation / updaterate;
-
- const double cos_dir = cos( shear_direction degrees);
- const double sin_dir = sin( shear_direction degrees);
-
- const double cos_squared = cos_dir * cos_dir;
- const double sin_squared = sin_dir * sin_dir;
- const double cos_sin = cos_dir * sin_dir;
-
- const double m = scaled_shear_magnitude;
- const double one_over_m = 1 / m;
-
- const double xform_0 = cos_squared * m + sin_squared / m;
- const double xform_1 = cos_sin * (m - one_over_m);
- const double xform_2 = xform_1;
- const double xform_3 = sin_squared * m + cos_squared / m;
- //
- // now apply the rotation:
- //
- // the transformation matrix for this operation is
- //
- // ( cos( r) -sin( r) )
- // ( sin( r) cos( r) )
- //
- const double cos_rot = cos( scaled_rotation degrees);
- const double sin_rot = sin( scaled_rotation degrees);
-
- double xform[ 4];
- xform[ 0] = cos_rot * xform_0 - sin_rot * xform_2;
- xform[ 1] = cos_rot * xform_1 - sin_rot * xform_3;
- xform[ 2] = sin_rot * xform_0 + cos_rot * xform_2;
- xform[ 3] = sin_rot * xform_1 + cos_rot * xform_3;
- //
- // apply the expansion (unrolling the loop):
- //
- xform[ 0] *= scaled_expansion;
- xform[ 1] *= scaled_expansion;
- xform[ 2] *= scaled_expansion;
- xform[ 3] *= scaled_expansion;
-
- x11 = (short)(long)((xform[ 0] - 1.0) * 0x8000);
- x12 = (short)(long)(xform[ 1] * 0x8000);
- x21 = (short)(long)(xform[ 2] * 0x8000);
- x22 = (short)(long)((xform[ 3] - 1.0) * 0x8000);
-
- trans_x = (long)(translation_x * 0x10000 / updaterate);
- trans_y = (long)(translation_y * 0x10000 / updaterate);
- }
-
- void flowdots::setsettings( const flowsettings &thesettings)
- {
- *((flowsettings *)this) = thesettings;
- changed();
- }
-
- void flowdots::setsettings( const flowparams &theparams)
- {
- //
- // This safety check could be added, but this function is written to obtain speed,
- // so we leave it out for the moment.
- //
- // if( how_often == 0.0)
- // {
- // DebugStr( "\pflowdots::setsettings( flowparams) called while how_often == 0.0");
- // }
- //
- *((flowparams *)this) = theparams;
- }
-